﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;

namespace xUnitTester.ControllerTesting
{
    public class EditorControllerTesting
    {
        [Fact]
        public void CancelMethod()
        {
            var ctl = new SVN.Net.Controllers.EditorController();
            var session = new System.Web.SessionState.SessionStateItemCollection();
            session["uid"] = "username";
            session["pwd"] = "password";
            ctl.ControllerContext = new MvcFakes.FakeControllerContext(ctl, session);

            var result = ctl.Cancel("");

            Assert.IsType<System.Web.Mvc.RedirectToRouteResult>(result);
        }

        public class EditSingleFileTesting
        {
            System.Web.SessionState.SessionStateItemCollection _session;

            public EditSingleFileTesting()
            {
                _session = new System.Web.SessionState.SessionStateItemCollection();
                _session["uid"] = "username";
                _session["pwd"] = "password";
            }

            private void InjectControllerContext(System.Web.Mvc.Controller ctl)
            {
                ctl.ControllerContext = new MvcFakes.FakeControllerContext(ctl, _session);
            }

            [Fact]
            public void EditMethod_Get_Exception()
            {
                var svnResult = new SVN.Net.Models.SVN.ProcessResult(false, "", "Error when SVN.Cat.");
                var moqSVN = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSVN.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.Cat(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(svnResult);
                var ctl = new SVN.Net.Controllers.EditorController(moqSVN.Object);
                InjectControllerContext(ctl);

                Assert.Throws<SVN.Net.Models.SVN.SvnException>("Error when SVN.Cat.", () => ctl.Edit("file:///D:/svn.net/repo/trunk/new_code2.txt"));
            }

            [Fact]
            public void EditMethod_Get_Success()
            {
                var svnResult = new SVN.Net.Models.SVN.ProcessResult(true, Properties.Resources.new_code2, "");
                var moqSVN = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSVN.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.Cat(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(svnResult);
                var ctl = new SVN.Net.Controllers.EditorController(moqSVN.Object);
                InjectControllerContext(ctl);

                var result = ctl.Edit("file:///D:/svn.net/repo/trunk/new_code2.txt");

                Assert.IsType<System.Web.Mvc.ViewResult>(result);

                Assert.Equal<int>(3, ctl.ViewData.Count);
                Assert.Equal<bool>(false, (bool)ctl.ViewData["isnew"]);
                Assert.Equal<string>("file:///D:/svn.net/repo/trunk/new_code2.txt", (string)ctl.ViewData["repo"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["name"]);

                Assert.IsType<string>(ctl.ViewData.Model);
                Assert.Equal<string>(Properties.Resources.new_code2, (string)ctl.ViewData.Model);
            }

            [Fact]
            public void EditMethod_Post_SvnCheckOutException()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                var svnResult = new SVN.Net.Models.SVN.ProcessResult(false, "", "Error when checkout.");
                string localPath = "";
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.CheckOut(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), ref localPath)).Returns(svnResult);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                Assert.Throws<SVN.Net.Models.SVN.SvnException>(() => ctl.Edit("file:///D:/svn.net/repo/trunk/new_code2.txt", Properties.Resources.new_code2, ""));
            }

            [Fact]
            public void EditMethod_Post_FileWriterException()
            {
                var svnResult = new SVN.Net.Models.SVN.ProcessResult(true, "", "");
                string localPath = "";
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.CheckOut(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), ref localPath)).Returns(svnResult);
                var moqFileWriter = new Moq.Mock<SVN.Net.Misc.FileWriter.IFileWriter>();
                moqFileWriter.Expect(fw => fw.Write(Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Throws(new Exception("File writer exception."));
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);
                ctl.FileWriter = moqFileWriter.Object;

                Assert.Throws<Exception>("File writer exception.", () => ctl.Edit("file:///D:/svn.net/repo/trunk/new_code2.txt", Properties.Resources.new_code2, ""));
            }

            [Fact]
            public void EditMethod_Post_SvnCommitException()
            {
                var svnCheckoutResult = new SVN.Net.Models.SVN.ProcessResult(true, "", "");
                var svnCommitResult = new SVN.Net.Models.SVN.ProcessResult(false, "", "Exception when commit.");
                string localPath = "";
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.CheckOut(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), ref localPath)).Returns(svnCheckoutResult);
                localPath = @"D:\svn.net\trunk\new_code2.txt";
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.CommitSingleFile(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(svnCommitResult);
                var moqFileWriter = new Moq.Mock<SVN.Net.Misc.FileWriter.IFileWriter>();
                moqFileWriter.Expect(fw => fw.Write(Moq.It.IsAny<string>(), Moq.It.IsAny<string>()));
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                Assert.Throws<SVN.Net.Models.SVN.SvnException>("Exception when commit.", () => ctl.Edit("file:///D:/svn.net/repo/trunk/new_code2.txt", Properties.Resources.new_code2, ""));
            }

            [Fact]
            public void EditMethod_Post_Success()
            {
                var svnCheckoutResult = new SVN.Net.Models.SVN.ProcessResult(true, "", "");
                var svnCommitResult = new SVN.Net.Models.SVN.ProcessResult(true, "", "");
                string localPath = "";
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.CheckOut(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), ref localPath)).Returns(svnCheckoutResult);
                localPath = @"D:\svn.net\trunk\new_code2.txt";
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.CommitSingleFile(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(svnCommitResult);
                var moqFileWriter = new Moq.Mock<SVN.Net.Misc.FileWriter.IFileWriter>();
                moqFileWriter.Expect(fw => fw.Write(Moq.It.IsAny<string>(), Moq.It.IsAny<string>()));
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                var result = ctl.Edit("file:///D:/svn.net/repo/trunk/new_code2.txt", Properties.Resources.new_code2, "");

                Assert.IsType<System.Web.Mvc.RedirectToRouteResult>(result);
            }
        }

        public class RenameFileFolderTesting
        {
            System.Web.SessionState.SessionStateItemCollection _session;

            public RenameFileFolderTesting()
            {
                _session = new System.Web.SessionState.SessionStateItemCollection();
                _session["uid"] = "username";
                _session["pwd"] = "password";
            }

            private void InjectControllerContext(System.Web.Mvc.Controller ctl)
            {
                ctl.ControllerContext = new MvcFakes.FakeControllerContext(ctl, _session);
            }

            [Fact]
            public void RenameMethod_Get()
            {
                var ctl = new SVN.Net.Controllers.EditorController();

                var result = ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt");

                Assert.IsType<System.Web.Mvc.ViewResult>(result);
                Assert.Equal<int>(3, ctl.ViewData.Count);
                Assert.Equal<string>("file:///D:/svn.net/repo/trunk/new_code2.txt", (string)ctl.ViewData["repo"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["currentFileName"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["newFileName"]);
            }

            [Fact]
            public void RenameMethod_Post_ValidationFailed_NullFileName1()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<bool>(svn => svn.Exist(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(false);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                var result = ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt", "new_code2.txt", "", "Auto test message.");

                Assert.IsType<System.Web.Mvc.ViewResult>(result);
                Assert.Equal<int>(4, ctl.ViewData.Count);
                Assert.Equal<string>("file:///D:/svn.net/repo/trunk/new_code2.txt", (string)ctl.ViewData["repo"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["currentFileName"]);
                Assert.Equal<string>("", (string)ctl.ViewData["newFileName"]);
                Assert.Equal<string>("Auto test message.", (string)ctl.ViewData["message"]);

                Misc.AssertHelper.VerifyModelState(ctl, "newFileName", "Mandatory field.");
            }

            [Fact]
            public void RenameMethod_Post_ValidationFailed_NullFileName2()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<bool>(svn => svn.Exist(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(false);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                var result = ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt", "new_code2.txt", "   ", "Auto test message.");

                Assert.IsType<System.Web.Mvc.ViewResult>(result);
                Assert.Equal<int>(4, ctl.ViewData.Count);
                Assert.Equal<string>("file:///D:/svn.net/repo/trunk/new_code2.txt", (string)ctl.ViewData["repo"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["currentFileName"]);
                Assert.Equal<string>("", (string)ctl.ViewData["newFileName"]);
                Assert.Equal<string>("Auto test message.", (string)ctl.ViewData["message"]);

                Misc.AssertHelper.VerifyModelState(ctl, "newFileName", "Mandatory field.");
            }

            [Fact]
            public void RenameMethod_Post_ValidationFailed_InvalidChar()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<bool>(svn => svn.Exist(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(false);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                var result = ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt", "new_code2.txt", "new_c@de2.txt", "Auto test message.");

                Assert.IsType<System.Web.Mvc.ViewResult>(result);
                Assert.Equal<int>(4, ctl.ViewData.Count);
                Assert.Equal<string>("file:///D:/svn.net/repo/trunk/new_code2.txt", (string)ctl.ViewData["repo"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["currentFileName"]);
                Assert.Equal<string>("new_c@de2.txt", (string)ctl.ViewData["newFileName"]);
                Assert.Equal<string>("Auto test message.", (string)ctl.ViewData["message"]);

                Misc.AssertHelper.VerifyModelState(ctl, "newFileName", "Contains invalid char.");
            }

            [Fact]
            public void RenameMethod_Post_ValidationFailed_Existed()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                moqSvn.Expect<bool>(svn => svn.Exist(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(true);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                var result = ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt", "new_code2.txt", "new_code2.txt.new", "Auto test message.");

                Assert.IsType<System.Web.Mvc.ViewResult>(result);
                Assert.Equal<int>(4, ctl.ViewData.Count);
                Assert.Equal<string>("file:///D:/svn.net/repo/trunk/new_code2.txt", (string)ctl.ViewData["repo"]);
                Assert.Equal<string>("new_code2.txt", (string)ctl.ViewData["currentFileName"]);
                Assert.Equal<string>("new_code2.txt.new", (string)ctl.ViewData["newFileName"]);
                Assert.Equal<string>("Auto test message.", (string)ctl.ViewData["message"]);

                Misc.AssertHelper.VerifyModelState(ctl, "newFileName", "Existed on the server side.");
            }

            [Fact]
            public void RenameMethod_Post_SvnMoveException()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                var moveResult = new SVN.Net.Models.SVN.ProcessResult(false, "", "Exception when moving the file.");
                moqSvn.Expect<bool>(svn => svn.Exist(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(false);
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.Move(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(moveResult);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                Assert.Throws<SVN.Net.Models.SVN.SvnException>("Exception when moving the file.", () => ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt", "new_code2.txt", "new_code2.txt.new", "Auto test message."));
            }

            [Fact]
            public void RenameMethod_Post_Success()
            {
                var moqSvn = new Moq.Mock<SVN.Net.Models.ISVNProvider>();
                var moveResult = new SVN.Net.Models.SVN.ProcessResult(true, "", "");
                moqSvn.Expect<bool>(svn => svn.Exist(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(false);
                moqSvn.Expect<SVN.Net.Models.SVN.ProcessResult>(svn => svn.Move(Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(moveResult);
                var ctl = new SVN.Net.Controllers.EditorController(moqSvn.Object);
                InjectControllerContext(ctl);

                var result = ctl.Rename("file:///D:/svn.net/repo/trunk/new_code2.txt", "new_code2.txt", "new_code2.txt.new", "Auto test message.");

                Assert.IsType<System.Web.Mvc.RedirectToRouteResult>(result);
            }

        }
    }
}
